#ifndef __TIME_SLOT_MANAGER_H__
#define __TIME_SLOT_MANAGER_H__

#include <rtdevice.h>

typedef struct
{
    unsigned int user_id[16];
    unsigned int id_num;
} sf_recv_info_t;

/**
 * @brief 分时收发配置结构体
 *
 */
typedef struct
{
    unsigned int alive_timeout;              /**< 保活超时时间，0：关闭，大于1：开启。开启此功能后，在ID资源不够时，有新的终端接入，将遍历信任列表，查询保活时间是否超时，若有
                                              超时终端（超时是指在超过alive_timeout没收到任何数据），则会直接将该超时终端剔除，以让出资源给新终端，单位：毫秒 */
    unsigned int data_transport_period;      /**< 数据收发周期 */
    unsigned short ul_max_len;               /**< 上行数据的最大长度 */
    unsigned short dl_max_len;               /**< 下行数据的最大长度 */
    unsigned char ul_resend_times;           /**< 上行数据的重发次数 */
    unsigned char dl_resend_times;           /**< 下行数据的重发次数 */
    unsigned char ul_mcs;                    /**< 上行数据的MCS */
    unsigned char dl_mcs;                    /**< 下行数据的MCS */
    unsigned short bc_frame_send_period;     /**< WIoTa广播帧发送周期 */
    unsigned short device_access_max;        /**< 设备接入最大数量 */
    unsigned int real_data_transport_period; /**< 实际上行数据的发送周期 */
} slot_rs_cfg_t;

/**
 * @brief  广播时隙信息结构体
 *
 */
typedef struct
{
    unsigned int pof;           /**< 发送周期有多少个整帧，period of fn = send_period(us) * 1000 / frame_len(us) + 1，向上取整为auth_period的整倍数 */
    unsigned char auth_period;  /**< 鉴权消息发送周期，单位为帧 */
    unsigned char resend_times; /**< 终端上行重发次数, 0表示不重发，1表示重发一次，2表示重发两次，以此类推 */
    unsigned char mcs;          /**< 终端上行active mcs */
    unsigned char na;           /**< 对齐 */
    unsigned int frame_num;     /**< AP当前帧号 */
} time_slot_bc_t;

typedef struct
{
    rt_list_t node;
    void *data;            // 分时发送模式下的下行数据
    unsigned int data_len; // 分时发送模式下的下行数据长度
} sf_data_node_t;

typedef struct
{
    rt_list_t data_list;   // 下行数据链表节点为sf_data_node_t
    unsigned int wiota_id; // 终端ID
} sf_send_info_t;

typedef struct
{
    sf_send_info_t *sf_send;   // 时隙上的终端信息，包含终端ID和下行数据
    unsigned short dev_num;    // 该时隙位置上的终端个数
    unsigned short ts_fn;      // 时隙分配值
    unsigned int frame_num;    // 当前帧号
    unsigned char ul_recv_fns; // 该时隙上行接收帧数
    unsigned char dl_send_fns; // 该时隙下行发送帧数
    unsigned short ts_index;   // 当前时隙号
} sf_info_t;

/**
 * @brief  计算时隙信息
 *
 * @param  slot_cfg        时隙配置
 * @param  ts_info         网关广播分时发送信息结构计算返回
 * @param  data_trans_info 一次数据传输要发送多少帧，用于网关分配发送时隙的计算
 * @return int             数据计算结果 0:成功; <0:失败
 */
int manager_time_slot_info_update(void *slot_cfg, void *ts_info, void *data_trans_info);

/**
 * @brief 初始化时隙信息，必须在网关ID管理初始化之后调用
 *
 * @param slot_rs_cfg            分时收发配置
 * @param bc_time_slot_info_cb   广播时隙信息回调函数，为空时表示不发送广播时隙信息
 * @param uc_fn_refresh_callback 帧号更新回调函数
 * @return int                   0成功; 非0失败
 */
int manager_time_slot_info_init(slot_rs_cfg_t *slot_rs_cfg, void(*bc_time_slot_info_cb), void(*uc_fn_refresh_callback));

/**
 * @brief 反初始化时隙信息
 *
 */
void manager_time_slot_info_deinit(void);

/**
 * @brief 更新时隙分配值，随着鉴权成功终端个数增多，鉴权时隙逐渐减少
 *
 */
void manager_update_ul_time_slot_fn(void);

/**
 * @brief  获取时隙分配值，实际为空闲时隙的最大值，从大到小分配
 *
 * @return unsigned short 实际空闲的时隙值
 */
unsigned short manager_get_ul_time_slot_fn(void);

/**
 * @brief  时隙分配值初始化
 *
 */
void manager_ul_time_slot_fn_init(void);

/**
 * @brief 定帧收发初始化
 *
 *@param slot_rs_cfg            时隙收发配置
 *@param uc_fn_refresh_callback 帧号刷新回调
 */
void manager_recv_send_by_fn_init(slot_rs_cfg_t *slot_rs_cfg, void(*uc_fn_refresh_callback));

/**
 * @brief  定帧接收，根据时隙分配值，将收到的帧号和用户ID存入数组
 *
 * @param wiota_id      用户ID
 * @param cur_time_slot 当前时隙
 *
 * @return int          0表示成功，其他则表示失败
 *
 */
int manager_add_recv_send_by_fn_info(unsigned int wiota_id, unsigned int cur_time_slot);

/**
 * @brief 如果时分时收发模式，则缓存下行定帧数据
 *
 * @param data          编码后的数据
 * @param data_len      数据长度
 * @param wiota_id      用户ID
 * @param cur_time_slot 当前时隙
 *
 * @return int          0表示数据已缓存，其他则表示不需要缓存或缓存失败
 */
int manager_cache_recv_send_data_by_fn(unsigned char *data, unsigned int data_len, unsigned int wiota_id, unsigned int cur_time_slot);

/**
 * @brief  获取数组下标，实际上是时隙分配值去掉鉴权帧数所在的实际位置
 *
 * @param  time_slot_fn 当前时隙值
 * @return int 数组下标 <0 表示无效
 */
int manager_get_ul_time_slot_fn_pos(int time_slot_fn);

/**
 * @brief 根据帧号获取当前时隙的定帧收发信息
 *
 * @param frame_num  当前帧号
 * @return sf_info_t 不为RT_NULL表示时隙有效，为NULL表示无效
 */
sf_info_t *manager_get_sf_info_by_fn(unsigned int frame_num);

/**
 * @brief 分时模式缓存数据长度回退
 *
 * @param revert_len 回退的长度
 */
void manager_cache_size_revert(unsigned int revert_len);

/**
 * @brief 分时模式缓存数据长度增加
 *
 * @param add_len 增加的长度
 */
int manager_cache_size_add(unsigned int add_len);

/**
 * @brief 获取定帧收发结构体指针
 *
 * @return sf_info_t* 定帧收发结构体指针
 */
sf_info_t *manager_get_sf_info_addr(void);

/**
 * @brief 获取是否为分时模式
 *
 * @return unsigned char 是否为分时模式
 */
unsigned char manager_get_is_ts_mode(void);

/**
 * @brief 获取总时隙数
 *
 * @return int 总时隙数
 */
int manager_get_time_slot_num(void);

#endif // __TIME_SLOT_MANAGER_H__